home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / BORLAND TURBO / TUTORIAL.PAK / OCFHLPR.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  19.5 KB  |  947 lines

  1. // ---------------------------------------------------------------------------
  2. // Copyright (C) 1994 Borland International
  3. // ---------------------------------------------------------------------------
  4. #include <ocf/pch.h>
  5. #include <ocf/ocapp.h>
  6. #include <ocf/ocdoc.h>
  7. #include <ocf/ocview.h>
  8. #include <ocf/ocremvie.h>
  9. #include <ocf/ocpart.h>
  10. #include <windowsx.h>
  11.  
  12. #include "ocfhlpr.h"
  13. #include "ocfhlpr.rh"
  14.  
  15. //
  16. // constants for menu enabling/disabling
  17. //
  18. const int MF_ON = MF_ENABLED;
  19. const int MF_OFF= MF_DISABLED|MF_GRAYED;
  20. const int MENU_GROUP_COUNT = 6;   // sizeof(TOcMenuDescr.Width) /
  21.                                   // sizeof(TOcMenuDescr.Width[0])
  22.  
  23. //
  24. // The TOcApp* pointer ...
  25. //
  26. static TOcApp*  TheOcApp = 0;
  27.  
  28.  
  29. //
  30. // Initializes OLE to use default IMalloc allocator.
  31. // Creates OCF helper objects
  32. //
  33. TOleInitEx::TOleInitEx(TRegList& regInfo,
  34.                        TComponentFactory callback,
  35.                        string& cmdLine, TRegLink* linkHead,
  36.                        HINSTANCE hInst) 
  37.            : OcRegistrar(0), OcApp(TheOcApp)
  38. {
  39.   // Initialize OCF objects: Create TOcRegistrar & TOcApp
  40.   //
  41.   OcRegistrar = new TOcRegistrar(regInfo, callback, cmdLine,
  42.                                  linkHead, hInst);
  43.   OcRegistrar->CreateOcApp(OcRegistrar->GetOptions(), OcApp);
  44. }
  45.  
  46.  
  47. //
  48. // Cleans up the OCF helper objects
  49. //
  50. TOleInitEx::~TOleInitEx()
  51. {
  52.   // Free the Registrar
  53.   //
  54.   delete OcRegistrar;
  55. }
  56.  
  57.  
  58. //
  59. // Accessor to the OcApp helper object - used mainly by OLE Window
  60. //
  61. TOcApp*
  62. GetOcApp()
  63. {
  64.   return TheOcApp;
  65. }
  66.  
  67.  
  68. //
  69. // Constructor of object encapsulating an OLE Frame window
  70. //
  71. TOleFrameWin::TOleFrameWin(HWND hwnd) :
  72.   Hwnd(hwnd)
  73. {
  74. }
  75.  
  76.  
  77. //
  78. // Method to call when OLE Frame Window receives a WM_CREATE message
  79. //
  80. void
  81. TOleFrameWin::OnCreate()
  82. {
  83.   // Hand our frame HWND to OCF so it may send OLE notifications/requests
  84.   //
  85.   if (GetOcApp())
  86.     GetOcApp()->SetupWindow(Hwnd);
  87. }
  88.  
  89.  
  90. //
  91. // Method to call when OLE Frame Window receives a WM_DESTROY message
  92. //
  93. void
  94. TOleFrameWin::OnDestroy()
  95. {
  96.   // Release the OCF Application helper object
  97.   //
  98.   if (GetOcApp())
  99.     GetOcApp()->Release();
  100. }
  101.  
  102.  
  103. //
  104. // Method to call when OLE Frame Window receives a WM_ACTIVATEAPP message
  105. //
  106. void
  107. TOleFrameWin::OnActivateApp(bool active)
  108. {
  109.   GetOcApp()->EvActivate(active);
  110. }
  111.  
  112.  
  113. //
  114. // Constructor of object encapsulating an OLE Window
  115. // Simply initialize OCF Helper objects
  116. //
  117. TOleWin::TOleWin(HWND hwnd) : Hwnd(hwnd),
  118.                               Pos(0, 0, 0, 0),
  119.                               Embedded(false),
  120.                               ShowObjects(true)
  121. {
  122.   OcDoc     = 0;
  123.   OcView    = 0;
  124.   DragPart  = 0;
  125.  
  126.   //
  127.   // Init menu related variables
  128.   //
  129.   MergedMenu = 0;
  130.   HMenu      = 0;
  131.   memset(Width, 0, sizeof(Width));
  132. }
  133.  
  134.  
  135. //
  136. // Method to call when OLE Window receives a WM_CREATE message
  137. //
  138. void
  139. TOleWin::OnCreate()
  140. {
  141.   // Create OCF Document/View pair associated with each OLE Window
  142.   //
  143.   OcDoc  = new TOcDocument(*GetOcApp());
  144.   OcView = new TOcView(*OcDoc);
  145.  
  146.   // Hand OCF our window handle so it may send OLE notifications/requests
  147.   //
  148.   if (OcView)
  149.     OcView->SetupWindow(Hwnd);
  150. }
  151.  
  152.  
  153. //
  154. // Method to call when OLE Window receives a WM_DESTROY message
  155. //
  156. void
  157. TOleWin::OnDestroy()
  158. {
  159.   // Deactivate the embedded parts
  160.   //
  161.   for (TOcPartCollectionIter i(OcDoc->GetParts()); i; i++) {
  162.     TOcPart& p = *i.Current();
  163.     p.Activate(false);
  164.   }
  165.  
  166.   // Release the OCF View helper object
  167.   //
  168.   if (OcView) {
  169.     OcView->EvClose();
  170.     OcView->ReleaseObject();
  171.   }
  172.  
  173.   // Close the OCF document helper object
  174.   //
  175.   if (OcDoc)
  176.     OcDoc->Close();
  177.  
  178.   // Delete the OCF document helper object
  179.   //
  180.   delete OcDoc;
  181. }
  182.  
  183.  
  184. //
  185. // Method to call when OLE Window receives a WM_SIZE message
  186. //
  187. void
  188. TOleWin::OnSize()
  189.  
  190. {
  191.   // Inform the OCF View helper that we've been resized
  192.   //
  193.   if (OcView)
  194.     OcView->EvResize();
  195. }
  196.  
  197.  
  198. //
  199. // Method to call when OLE Window receives a WM_PAINT message.
  200. // Asks parts to draw themselves
  201. //
  202. void
  203. TOleWin::OnPaint(HDC dc, PAINTSTRUCT& ps)
  204. {
  205.   bool metafile = GetDeviceCaps(dc, TECHNOLOGY) == DT_METAFILE;
  206.   SetupDC(dc, !metafile);
  207.  
  208.   PaintParts(dc, ps.fErase, TRect(ps.rcPaint), metafile);
  209. }
  210.  
  211.  
  212. //
  213. // Method to call when OLE Window receives a WM_COMMAND with an
  214. // id it does not care for. This method handles the various
  215. // OLE UI commands such as InsertObject or PasteSpecial
  216. //
  217. bool
  218. TOleWin::OnCommand(uint cmdID)
  219. {
  220.   switch (cmdID) {
  221.     case CM_EDITINSERTOBJECT:
  222.       EditInsertObject();
  223.       break;
  224.  
  225.     case CM_EDITPASTESPECIAL:
  226.       EditPasteSpecial();
  227.       break;
  228.  
  229.     case CM_EDITCONVERT:
  230.       EditConvert();
  231.       break;
  232.  
  233.     case CM_EDITLINKS:
  234.       EditLinks();
  235.       break;
  236.  
  237.     case CM_EDITSHOWOBJECTS:
  238.       ShowObjects = !ShowObjects;
  239.       InvalidateRect(Hwnd, 0, TRUE);
  240.       break;
  241.  
  242.     default:
  243.       return false;       // We did not handle the command!
  244.   }
  245.   return true;            // We handled the command
  246. }
  247.  
  248.  
  249. //
  250. //
  251. //
  252. void
  253. TOleWin::OnInitMenu(HMENU hMenu)
  254. {
  255.  
  256.   EnableMenuItem(hMenu, CM_EDITINSERTOBJECT, MF_BYCOMMAND |
  257.                  ((GetOcApp() && GetOcView()) ? MF_ON : MF_OFF));
  258.   EnableMenuItem(hMenu, CM_EDITCONVERT,
  259.               MF_BYCOMMAND|((DragPart != 0) ? MF_ON : MF_OFF));
  260.  
  261.   uint mask = GetOcApp()->EnableEditMenu(
  262.                   TOcMenuEnable(meEnablePaste|meEnablePasteLink|
  263.                                 meEnableBrowseClipboard|meEnableBrowseLinks),
  264.                                          GetOcView());
  265.  
  266.   EnableMenuItem(hMenu, CM_EDITPASTE,
  267.               MF_BYCOMMAND|((mask & meEnablePaste) ? MF_ON : MF_OFF));
  268.   EnableMenuItem(hMenu, CM_EDITPASTELINK,
  269.               MF_BYCOMMAND|((mask & meEnablePasteLink) ? MF_ON : MF_OFF));
  270.   EnableMenuItem(hMenu, CM_EDITPASTESPECIAL,
  271.               MF_BYCOMMAND|((mask & meEnableBrowseClipboard) ? MF_ON : MF_OFF));
  272.   EnableMenuItem(hMenu, CM_EDITLINKS,
  273.               MF_BYCOMMAND|((mask & meEnableBrowseLinks) ? MF_ON : MF_OFF));
  274.  
  275.   CheckMenuItem(hMenu, CM_EDITSHOWOBJECTS,
  276.                 MF_BYCOMMAND |(ShowObjects ? MF_CHECKED : MF_UNCHECKED));
  277. }
  278.  
  279.  
  280. //
  281. // Method to call when OLE Window receives a WM_INITMENUPOPUP message
  282. // (which is typically a hand-down from the frame window).
  283. // Method takes care of enabling/disabling/checking etc. OLE related
  284. // commands.
  285. //
  286. void
  287. TOleWin::OnInitMenuPopup(HMENU hMenu, int /*item*/)
  288. {
  289.   OnInitMenu(hMenu);
  290. }
  291.  
  292.  
  293. //
  294. // Method to call when OLE Window receives a WM_LBUTTONDOWN message.
  295. // Deactivates any active parts.
  296. //
  297. bool
  298. TOleWin::OnLButtonDown(int /*x*/, int /*y*/, UINT /*keyFlags*/)
  299. {
  300.   if (Deactivate())
  301.     return true;        // We handled the message...
  302.  
  303.   return false;
  304. }
  305.  
  306.  
  307. //
  308. // Method to call when OLE Window receives an WM_LBUTTONDBLCLK message.
  309. // Activates the part if the mouse was clicked on an inactivate part.
  310. //
  311. bool
  312. TOleWin::OnLButtonDblClk(int x, int y, UINT modKeys)
  313. {
  314.   TPoint point(x, y);
  315.   OleClientDC dc(*this);
  316.   DPtoLP(dc, &point, 1);
  317.  
  318.   TOcPart* p = GetOcDoc()->GetParts().Locate(point);
  319.  
  320.   if (modKeys & MK_CONTROL) {
  321.     if (p)
  322.       p->Open(true);
  323.   } else {
  324.     SetSelection(p);
  325.  
  326.     if (p && p == GetOcView()->GetActivePart())
  327.       p->Activate(false);
  328.  
  329. #if !defined(BOLE_ACTIVATE)
  330.     GetOcView()->ActivatePart(p);
  331. #else
  332.     if (p)
  333.       p->Activate(true);
  334. #endif
  335.   }
  336.  
  337.   return true;
  338. }
  339.  
  340.  
  341. //
  342. // Method to call when OLE window receives a WM_ACTIVATE or
  343. // WM_MDIACTIVATE message.
  344. //
  345. void
  346. TOleWin::OnActivate(bool active)
  347. {
  348.   GetOcView()->EvActivate(active);
  349. }
  350.  
  351.  
  352. //
  353. //
  354. //
  355. void
  356. TOleWin::OnSetFocus(HWND /*hwndLostFocus*/)
  357. {
  358.   GetOcView()->EvSetFocus(true);
  359. }
  360.  
  361.  
  362. //
  363. // Method to call when OLE Window receives a WM_RBUTTONDOWN message.
  364. // Implements the Local Object menu (with VERBS) if the mouse was
  365. // clicked on a part.
  366. //
  367. bool
  368. TOleWin::OnRButtonDown(int /*x*/, int /*y*/, uint /*keyFlags*/)
  369. {
  370.   return true;
  371. }
  372.  
  373.  
  374. //
  375. // Method to call when OLE Window receives a WM_OCEVENT message.
  376. // This method invokes a separate handler for the various OCF
  377. // events. These in turn provide various default behaviours.
  378. //
  379. LRESULT
  380. TOleWin::OnOcEvent(WPARAM wParam, LPARAM lParam)
  381. {
  382.   switch (wParam) {
  383.     case OC_VIEWTITLE:
  384.          return (LRESULT)OnOcViewTitle();
  385.  
  386.     case OC_VIEWSETTITLE:
  387.          OnOcViewSetTitle((const char far*)lParam);
  388.          return (LRESULT)true;
  389.  
  390.     case OC_VIEWSETSITERECT:
  391.          return (LRESULT)OnOcViewSetSiteRect((TRect far*)lParam);
  392.  
  393.     case OC_VIEWGETSCALE:
  394.          return (LRESULT)OnOcViewGetScale((TOcScaleFactor far*)lParam);
  395.  
  396.     case OC_VIEWPARTINVALID:
  397.          return (LRESULT)OnOcViewPartInvalid((TOcPartChangeInfo far*)lParam);
  398.  
  399.     case OC_VIEWGETSITERECT:
  400.           return (LRESULT)OnOcViewGetSiteRect((TRect far*)lParam);
  401.  
  402.     case OC_VIEWDROP:
  403.          return OnOcViewDrop((TOcDragDrop far*)lParam);
  404.  
  405.     default:
  406.       return LRESULT(false);
  407.   }
  408. }
  409.  
  410.  
  411. const char*
  412. TOleWin::OnOcViewTitle()
  413. {
  414.   static char title[100];
  415.  
  416.   if (IsWindow(Hwnd)) {
  417.     GetWindowText(Hwnd, title, sizeof(title));
  418.   }
  419.   return title;
  420. }
  421.  
  422.  
  423. void
  424. TOleWin::OnOcViewSetTitle(const char far* text)
  425. {
  426.   if (IsWindow(Hwnd))
  427.     SetWindowText(Hwnd, text);
  428. }
  429.  
  430.  
  431. bool
  432. TOleWin::OnOcViewGetScale(TOcScaleFactor* scaleInfo)
  433. {
  434.   if (scaleInfo)
  435.     *scaleInfo = Scale;
  436.  
  437.   return true;
  438. }
  439.  
  440.  
  441. bool
  442. TOleWin::OnOcViewSetSiteRect(TRect far* rect)
  443. {
  444.   OleClientDC dc(*this);
  445.   return DPtoLP(dc, (POINT*)rect, 2);
  446. }
  447.  
  448.  
  449. bool
  450. TOleWin::OnOcViewGetSiteRect(TRect far* rect)
  451. {
  452.   OleClientDC dc(*this);
  453.   return LPtoDP(dc, (POINT*)rect, 2);
  454.  
  455. }
  456.  
  457.  
  458. bool
  459. TOleWin::OnOcViewPartInvalid(TOcPartChangeInfo far* changeInfo)
  460. {
  461.   TRect rect(changeInfo->GetPart()->GetRect());
  462.   rect.right++;
  463.   rect.bottom++;
  464.  
  465.   OleClientDC dc(*this);
  466.   LPtoDP(dc, (TPoint*)&rect, 2);
  467.   InvalidateRect(Hwnd, &rect, true);
  468.   InvalidatePart((TOcInvalidate)changeInfo->GetType());
  469.   return true;
  470. }
  471.  
  472.  
  473. bool
  474. TOleWin::OnOcViewDrop(TOcDragDrop far*)
  475. {
  476.   //
  477.   // Answer positively: we'll take any drop
  478.   //
  479.   return true;
  480. }
  481.  
  482.  
  483. //
  484. // Displays the InsertObject dialog and allows user to
  485. // embed an object [newly created or created from file]
  486. //
  487. void
  488. TOleWin::EditInsertObject()
  489. {
  490.   try {
  491.     TOcInitInfo initInfo(OcView);
  492.     if (GetOcApp()->Browse(initInfo)) {
  493.       TRect rect;
  494.       GetInsertPosition(rect);
  495.       SetSelection(new TOcPart(*GetOcDoc(), initInfo, rect));
  496.  
  497.       OcView->Rename();
  498.       InvalidatePart(invView);
  499.     }
  500.   }
  501.   catch (TXBase& xbase) {
  502.     MessageBox(Hwnd, xbase.why().c_str(), "EXCEPTION: InsertObject", MB_OK);
  503.   }
  504. }
  505.  
  506.  
  507. //
  508. // Displays PasteSpecial dialog and allows use to paste/pasteLink
  509. // object current on the clipboard.
  510. //
  511. void
  512. TOleWin::EditPasteSpecial()
  513. {
  514.   try {
  515.     TOcInitInfo initInfo(GetOcView());
  516.  
  517.     if (GetOcView()->BrowseClipboard(initInfo)) {
  518.       TRect rect;
  519.       GetInsertPosition(rect);
  520.       new TOcPart(*GetOcDoc(), initInfo, rect);
  521.       initInfo.ReleaseDataObject();
  522.     }
  523.   }
  524.   catch (TXBase& xbase) {
  525.     MessageBox(Hwnd, xbase.why().c_str(), "EXCEPTION: PasteSpecial", MB_OK);
  526.   }
  527. }
  528.  
  529.  
  530. void
  531. TOleWin::EditConvert()
  532. {
  533.   GetOcApp()->Convert(DragPart, false);
  534. }
  535.  
  536.  
  537. void
  538. TOleWin::EditLinks()
  539. {
  540.   GetOcView()->BrowseLinks();
  541. }
  542.  
  543.  
  544. //
  545. //
  546. //
  547. bool
  548. TOleWin::SelectEmbedded()
  549. {
  550.   return DragPart != 0;
  551. }
  552.  
  553.  
  554. void
  555. TOleWin::InvalidatePart(TOcInvalidate invalid)
  556. {
  557.   if (GetOcRemView())
  558.     GetOcRemView()->Invalidate(invalid);
  559. }
  560.  
  561.  
  562. //
  563. //
  564. //
  565. bool
  566. TOleWin::Deactivate()
  567. {
  568.   if (DragPart && DragPart->IsActive()) {
  569.     SetSelection(0);
  570.     return true;
  571.   } else {
  572.     return false;
  573.   }
  574. }
  575.  
  576.  
  577. //
  578. //
  579. //
  580. void
  581. TOleWin::SetSelection(TOcPart* part)
  582. {
  583.   if (part == DragPart)
  584.     return;
  585.  
  586.   // Invalidate old part
  587.   //
  588.   TOcPartChangeInfo changeInfo(DragPart, invView);
  589.   if (DragPart) {
  590.     DragPart->Select(false);
  591. #if !defined(BOLE_ACTIVATE)
  592.     DragPart->Activate(false);
  593. #endif
  594.     OnOcViewPartInvalid(&changeInfo);
  595.   }
  596.  
  597.   // Select and invalidate new one
  598.   //
  599.   DragPart = part;
  600.   changeInfo.SetPart(DragPart);
  601.   if (DragPart) {
  602.     part->Select(true);
  603.     OnOcViewPartInvalid(&changeInfo);
  604.   }
  605. }
  606.  
  607.  
  608. //
  609. //
  610. //
  611. void
  612. TOleWin::GetInsertPosition(TRect& rect)
  613. {
  614.   OleClientDC dc(*this);
  615.  
  616.   // Default to 0.5" from viewport origin
  617.   //
  618.   rect.left  = rect.top = 0;
  619.   rect.right = GetDeviceCaps(dc, LOGPIXELSX) >> 1;
  620.   rect.bottom= GetDeviceCaps(dc, LOGPIXELSY) >> 1;
  621.  
  622.   LPtoDP(dc, (TPoint*)&rect, 2);
  623.  
  624.   // Embedded rect is in pixel
  625.   //
  626.   rect.left  = rect.Width();
  627.   rect.top   = rect.Height();
  628.   rect.right = rect.bottom = 0;
  629. }
  630.  
  631.  
  632. //
  633. // Get the logical unit per inch for document
  634. //
  635. void
  636. TOleWin::GetLogPerUnit(TSize& logPerUnit)
  637. {
  638.   HDC dc = GetWindowDC(0);  // Screen DC
  639.   logPerUnit.cx = GetDeviceCaps(dc, LOGPIXELSX);
  640.   logPerUnit.cy = GetDeviceCaps(dc, LOGPIXELSY);
  641.   ReleaseDC(0, dc);
  642. }
  643.  
  644.  
  645. void
  646. TOleWin::SetupDC(HDC dc, bool scale)
  647. {
  648.   SetMapMode(dc, MM_ANISOTROPIC);
  649.  
  650.   TPoint scrollPos(0, 0);
  651.  
  652.   // Adjust for scrolling here
  653.   //
  654.  
  655.   SetWindowOrgEx(dc, scrollPos.x, scrollPos.y, 0);
  656.  
  657.  
  658.   if (!scale)
  659.     return;
  660.  
  661.   SetViewportOrgEx(dc, Pos.left, Pos.top, 0);
  662.  
  663.   //
  664.   //
  665.   //
  666.   TSize ext;
  667.   GetLogPerUnit(ext);
  668.   SetWindowExtEx(dc, ext.cx, ext.cy, 0);
  669.  
  670.   ext.cx = GetDeviceCaps(dc, LOGPIXELSX);
  671.   ext.cy = GetDeviceCaps(dc, LOGPIXELSY);
  672.  
  673.  
  674.   ext.cx = (int)(((uint32)ext.cx * Scale.SiteSize.cx + (Scale.PartSize.cx >> 1)) /
  675.                 Scale.PartSize.cx);
  676.   ext.cy = (int)(((uint32)ext.cy * Scale.SiteSize.cy + (Scale.PartSize.cy >> 1)) /
  677.                 Scale.PartSize.cy);
  678.  
  679.   SetViewportExtEx(dc, ext.cx, ext.cy, 0);
  680. }
  681.  
  682.  
  683. bool
  684. TOleWin::PaintParts(HDC dc, bool, TRect&, bool metafile)
  685. {
  686.   TRect clientRect;
  687.   TRect logicalRect;
  688.  
  689.   GetClientRect(Hwnd, &logicalRect);
  690.  
  691.   if (!IsEmbedded())
  692.     clientRect = logicalRect;
  693.   else {
  694.     GetWindowRect(Hwnd, &clientRect);
  695.     clientRect.Offset(-clientRect.left, -clientRect.top);
  696.   }
  697.  
  698.   TPoint scrollPos(0, 0);
  699.  
  700.   if (!metafile)
  701.     DPtoLP(dc, (TPoint*)&logicalRect, 2);
  702.  
  703.   for (TOcPartCollectionIter i(GetOcDoc()->GetParts()); i; i++) {
  704.     TOcPart& p = *i.Current();
  705.     if (p.IsVisible(logicalRect) || metafile) {
  706.       TRect r = p.GetRect();
  707.       r.Offset(-scrollPos.x, -scrollPos.y);
  708.       p.Draw(dc, r, clientRect, asDefault);
  709.  
  710.       if (metafile)
  711.         continue;
  712.  
  713.       // Paint selection
  714.       //
  715.       // >> Can draw selection (eg. XOR rectangle here)
  716.     }
  717.   }
  718.  
  719.   return true;
  720. }
  721.  
  722.  
  723. //
  724. // Sets and returns previous user-defined pointer which
  725. // can be stored along with the OCF helper.
  726. //
  727. void*
  728. TOleWin::SetUserInfo(void* ui)
  729. {
  730.   void* previous = UserInfo;
  731.   UserInfo = ui;
  732.   return previous;
  733. }
  734.  
  735.  
  736. //
  737. // Hands a menu handle and menu description to the OCF helper
  738. // object so the latter can handle OLE menu merging on behalf
  739. // of the window.
  740. //
  741. void
  742. TOleWin::SetWinMenu(const TOcMenuDescr& menuDescr)
  743. {
  744.   HMenu = menuDescr.HMenu;
  745.   if (HMenu)
  746.     memcpy(Width, menuDescr.Width, sizeof(Width));
  747.   else
  748.     memset(Width, 0, sizeof(Width));
  749. }
  750.  
  751.  
  752. //
  753. // Merge the container's menu in OLE's menu handle
  754. //
  755. bool
  756. TOleWin::OnOcAppInsMenus(TOcMenuDescr far* sharedMenu)
  757. {
  758.   //
  759.   // If we don't have a menu handle to merge, return false
  760.   //
  761.   if (!HMenu)
  762.     return false;
  763.  
  764.   //
  765.   // If we've merged into OLE's menu already, don't bother remerging
  766.   //
  767.   if(MergedMenu)
  768.     return true;
  769.  
  770.   //
  771.   // Merge the container menu in OLE's menu
  772.   //
  773.   MergeContainerMenu(*sharedMenu, *this);
  774.   return true;
  775.  
  776. }
  777.  
  778.  
  779. //
  780. // Handles OC_APPMENUS, a request to set a new menu bar
  781. // We return the handle so the frame may set the menu.
  782. //
  783. HMENU
  784. TOleWin::OnOcAppMenus(TOcMenuDescr far* menuDescr)
  785. {
  786.   //
  787.   // If OLE does not pass a handle, hand our original menu
  788.   //
  789.   if (!menuDescr->HMenu) {
  790.     MergedMenu = 0;
  791.     return HMenu;
  792.   }
  793.  
  794.   return MergedMenu ? MergedMenu : menuDescr->HMenu;
  795. }
  796.  
  797.  
  798. //
  799. //
  800. //
  801. HMENU
  802. TOleWin::OnOcAppRestoreUI()
  803. {
  804.   MergedMenu = 0;
  805.   return HMenu;
  806. }
  807.  
  808.  
  809. //
  810. // Merges source menu popups into the destination menu.
  811. // SrcOwnsEven determines whether the source or destination
  812. // own the even or odd entries within the menu.
  813. //
  814. static bool
  815. MergeMenu(MenuDescr& dst, const MenuDescr& src, bool srcOwnsEven)
  816. {
  817.   int dstOff = 0;
  818.   int srcOff = 0;
  819.  
  820.   for (int i=0; i<MENU_GROUP_COUNT; i++) {
  821.     if ((!(i%2) && srcOwnsEven) || ((i%2) && !srcOwnsEven)) {
  822.       // If the current location is owned by the source, there should
  823.       // not be anything there from the destination already.
  824.       //
  825.       if (dst.Width[i]) {
  826.         // However, if the entries are occupied,
  827.         // should they be removed/deleted - or should we just append ours?
  828.         //
  829.       }
  830.  
  831.       // If source has something to merge
  832.       //
  833.       if (src.Width[i]) {
  834.         // Iterate through the source's menu items
  835.         //
  836.         int insertCount = 0;
  837.         for (int j=0; j<src.Width[i]; j++) {
  838.           uint state = GetMenuState(src, srcOff+j, MF_BYPOSITION);
  839.  
  840.           // Validate source menu item
  841.           //
  842.           if (state == uint(-1))
  843.             break;
  844.  
  845.           // Retrieve string
  846.           //
  847.           char str[256];
  848.           GetMenuString(src, srcOff+j, str, sizeof(str), MF_BYPOSITION);
  849.  
  850.           // If it's a popup, we'll share the handle
  851.           //
  852.           uint idOrPopup;
  853.           if (state & MF_POPUP) {
  854.             state &= (MF_STRING|MF_POPUP);
  855.             HMENU sub = GetSubMenu(src, srcOff+j);
  856.             idOrPopup = UINT(sub);
  857.           } else {
  858.             idOrPopup = GetMenuItemID(src, srcOff+j);
  859.           }
  860.  
  861.           // Insert destination menu
  862.           //
  863.           if (GetMenuItemCount(dst) <= dstOff+j)
  864.             AppendMenu(dst, state|MF_BYPOSITION, idOrPopup, str);
  865.           else
  866.             InsertMenu(dst, dstOff+j, state|MF_BYPOSITION, idOrPopup, str);
  867.  
  868.           insertCount++;
  869.         }
  870.  
  871.         // Update dst. width by # of new entries we've added
  872.         //
  873.         dst.Width[i] += insertCount;
  874.       }
  875.     } else {
  876.       // Here, if src.Width[i] == -1, we could delete the destinations entries
  877.       //
  878.     }
  879.  
  880.     // Update offset by width of entries just processed.
  881.     //
  882.     srcOff += src.Width[i];
  883.     dstOff += dst.Width[i];
  884.   }
  885.  
  886.   return true;
  887. }
  888.  
  889.  
  890. //
  891. // Merge so that source (container) owns the even entries
  892. //
  893. bool
  894. MergeContainerMenu(TOcMenuDescr& dst, const TOcMenuDescr& src)
  895. {
  896.   return MergeMenu(*((MenuDescr*)&dst), *((MenuDescr*)&src), true);
  897. }
  898.  
  899.  
  900. //
  901. // Merge so that source (server) owns the odd entries
  902. //
  903. bool
  904. MergeServerMenu(TOcMenuDescr& dst, const TOcMenuDescr& src)
  905. {
  906.   return MergeMenu(*((MenuDescr*)&dst), *((MenuDescr*)&src), false);
  907. }
  908.  
  909.  
  910. //
  911. // Prompts user for a filename using Common Dialog
  912. //
  913. bool
  914. GetOpenFileName(HWND owner, const char* filter, char* fileName,
  915.                 int size, DWORD flags)
  916. {
  917.    OPENFILENAME ofn;
  918.    memset(&ofn, 0, sizeof(ofn));
  919.    ofn.lStructSize   = sizeof(ofn);
  920.    ofn.hwndOwner     = owner;
  921.    ofn.lpstrFilter   = filter;
  922.    ofn.lpstrFile     = fileName;
  923.    ofn.nMaxFile      = size;
  924.    ofn.Flags         = flags;
  925.    return GetOpenFileName(&ofn);
  926. }
  927.  
  928.  
  929. //
  930. // Prompts user for a filename using Common Dialog
  931. //
  932. bool
  933. GetSaveFileName(HWND owner, const char* filter, char* fileName,
  934.                 int size, DWORD flags)
  935. {
  936.    OPENFILENAME ofn;
  937.    memset(&ofn, 0, sizeof(ofn));
  938.    ofn.lStructSize   = sizeof(ofn);
  939.    ofn.hwndOwner     = owner;
  940.    ofn.lpstrFilter   = filter;
  941.    ofn.lpstrFile     = fileName;
  942.    ofn.nMaxFile      = size;
  943.    ofn.Flags         = flags;
  944.    return GetSaveFileName(&ofn);
  945. }
  946.  
  947.